home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993…ch: Other People's Memory / ADC Developer CD (1993-03) (''Other People's Memory'')_iso / Dev.CD Mar 93.iso / Technical Documentation / Sample Code / DTS.Lib & Samples / Kibitz / File.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-22  |  22.9 KB  |  869 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:            file.c
  5. ** Some code from:  Traffic Light 2.0 version, by Keith Rollin & John Harvey
  6. ** Modified by:     Eric Soldan
  7. **
  8. ** Copyright © 1990-1992 Apple Computer, Inc.
  9. ** All rights reserved. */
  10.  
  11.  
  12.  
  13. /*****************************************************************************/
  14.  
  15.  
  16.  
  17. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  18. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  19. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  20.  
  21. #ifndef __ALIASES__
  22. #include <Aliases.h>
  23. #endif
  24.  
  25. #ifndef __ERRORS__
  26. #include <Errors.h>
  27. #endif
  28.  
  29. #ifndef __MEMORY__
  30. #include <Memory.h>
  31. #endif
  32.  
  33. #ifndef __PACKAGES__
  34. #include <Packages.h>
  35. #endif
  36.  
  37. #ifndef __TOOLUTILS__
  38. #include <ToolUtils.h>
  39. #endif
  40.  
  41. #ifndef __UTILITIES__
  42. #include <Utilities.h>
  43. #endif
  44.  
  45.  
  46.  
  47. /*****************************************************************************/
  48.  
  49.  
  50.  
  51. static Boolean    gIncNewFileNumFlag = true;
  52.  
  53.  
  54.  
  55. /*****************************************************************************/
  56. /*****************************************************************************/
  57.  
  58.  
  59.  
  60. /* This function disposes of the document.  It checks to see if a file is
  61. ** currently open for the document.  If it is, then the document is closed.
  62. ** Once there is no open file for the document, the memory occupied by the
  63. ** document is released. */
  64.  
  65. #pragma segment File
  66. OSErr    AppDisposeDocument(FileRecHndl frHndl)
  67. {
  68.     OSErr        err;
  69.     Handle        snd;
  70.  
  71.     err = noErr;
  72.  
  73.     if (frHndl) {
  74.         SetOpponentType(frHndl, kOnePlayer);
  75.             /* Disconnect from opponent. */
  76.  
  77.         if ((*frHndl)->fileState.fss.vRefNum != kInvalVRefNum)
  78.             err = FSClose((*frHndl)->fileState.refNum);
  79.                 /* Close the file, if opened. */
  80.  
  81.         DisposHandle((Handle)(*frHndl)->doc.legalMoves);
  82.         DisposHandle((Handle)(*frHndl)->doc.gameMoves);
  83.         if (snd = (*frHndl)->doc.sound)
  84.             DisposHandle(snd);
  85.                 /* Release all handles hanging off the document. */
  86.  
  87.         DisposHandle((Handle)frHndl);
  88.             /* Release memory for the document handle. */
  89.     }
  90.  
  91.     return(err);
  92. }
  93.  
  94.  
  95.  
  96. /*****************************************************************************/
  97.  
  98.  
  99.  
  100. /* This function returns whether or not the document is dirty. */
  101.  
  102. #pragma segment File
  103. Boolean    AppDocumentDirty(FileRecHndl frHndl)
  104. {
  105.     return((*frHndl)->fileState.docDirty);
  106. }
  107.  
  108.  
  109.  
  110. /*****************************************************************************/
  111.  
  112.  
  113.  
  114. /* This function creates a new document.  A handle is created as the
  115. ** reference to the document.  Header information is placed in this handle.
  116. ** The application-specific data follows this header information.  The
  117. ** handle is returned (or nil upon failure), and typically the handle is
  118. ** then stored in the refCon field of the window.  Note that this is a
  119. ** convention, and is not mandatory.  This allows a document to exist that
  120. ** has no window.  A document with no window is useful when the application
  121. ** is called from the finder in response to a print request.  The document
  122. ** can be loaded and printed without involving a window on the screen. */
  123.  
  124.  
  125. #pragma segment File
  126. OSErr    AppNewDocument(FileRecHndl *returnHndl, short winNameType)
  127. {
  128.     static short    untitledCount;
  129.     FileRecHndl        frHndl;
  130.     FileRecPtr        frPtr;
  131.     Str255            untitled;
  132.     StringPtr        pstr;
  133.     MoveListHndl    legalMovesHndl;
  134.     GameListHndl    gameMovesHndl;
  135.  
  136.     *returnHndl = nil;
  137.  
  138.     if (frHndl = (FileRecHndl)NewHandle(sizeof(FileRec))) {
  139.  
  140.         GetIndString(untitled, rMiscStrings, winNameType);
  141.         frPtr = *frHndl;
  142.         frPtr->fileState.docDirty    = false;
  143.         frPtr->fileState.readOnly    = false;
  144.         frPtr->fileState.fss.vRefNum = kInvalVRefNum;
  145.         frPtr->fileState.window      = nil;
  146.         pstr = frPtr->fileState.fss.name;
  147.         pcpy(pstr, untitled);
  148.         if (gIncNewFileNumFlag) ++untitledCount;
  149.         pcatdec(pstr, untitledCount);
  150.  
  151.         legalMovesHndl = (MoveListHndl)NewHandle(0);
  152.         if (!legalMovesHndl) {
  153.             DisposHandle((Handle)frHndl);
  154.             return(memFullErr);
  155.         }
  156.  
  157.         gameMovesHndl = (GameListHndl)NewHandle(0);
  158.         if (!gameMovesHndl) {
  159.             DisposHandle((Handle)frHndl);
  160.             DisposHandle((Handle)legalMovesHndl);
  161.             return(memFullErr);
  162.         }
  163.  
  164.         NewGame(frHndl);        /* Initialize the game. */
  165.  
  166.         frPtr = *frHndl;
  167.         frPtr->doc.legalMoves = legalMovesHndl;
  168.         frPtr->doc.gameMoves  = gameMovesHndl;
  169.         if (winNameType == ksMssgName) frPtr->doc.myColor = kMessageDoc;
  170.  
  171.         *returnHndl = frHndl;
  172.         return(noErr);            /* All is well. */
  173.     }
  174.  
  175.     return(memFullErr);
  176. }
  177.  
  178.  
  179.  
  180. /*****************************************************************************/
  181.  
  182.  
  183.  
  184. #pragma segment File
  185. OSErr    AppOpenDocument(FileRecHndl *result, FSSpecPtr fileToOpen, char permission)
  186. {
  187.     StandardFileReply    reply;
  188.     short                fileRefNum;
  189.     FileRecHndl            frHndl;
  190.     OSErr                err;
  191.     FSSpec                myFileSpec;
  192.     DialogPtr            openDialog;
  193.     short                item, winNameType;
  194.  
  195.     *result = nil;        /* Assume we will fail. */
  196.  
  197.     if (!fileToOpen) {
  198.         if (DisplayGetFile(&reply))        /* Let the user decide which file. */
  199.             myFileSpec = reply.sfFile;    /* User's choice.                   */
  200.         else
  201.             return(userCanceledErr);    /* User canceled. */
  202.     }
  203.     else
  204.         myFileSpec = *fileToOpen;        /* Pre-designated file to open. */
  205.  
  206.     winNameType = ksOrigName;
  207.     if (reply.sfType != gameFileType) winNameType = ksMssgName;
  208.  
  209.     IncNewFileNum(false);
  210.     err = AppNewDocument(&frHndl, winNameType);
  211.     IncNewFileNum(true);
  212.     if (err) return(err);
  213.         /* We couldn't create an empty document, so give it up. */
  214.  
  215.     err = HOpen(myFileSpec.vRefNum, myFileSpec.parID,
  216.                 myFileSpec.name, permission, &fileRefNum);
  217.  
  218.     if (err == opWrErr) {
  219.  
  220.         ParamText(myFileSpec.name, nil, nil, nil);
  221.         openDialog = GetCenteredDialog(rOpenReadOnly, nil, nil, (WindowPtr)-1L);
  222.         if (!openDialog) {
  223.             AppDisposeDocument(frHndl);
  224.             return(err);
  225.         }
  226.  
  227.         OutlineDialogItem(openDialog, kOpenYes);
  228.         DoSetCursor(&qd.arrow);
  229.         ModalDialog((ModalFilterProcPtr)KeyEquivFilter, &item);
  230.         DisposDialog(openDialog);
  231.         if (item != kOpenYes) return(userCanceledErr);
  232.  
  233.         (*frHndl)->fileState.readOnly = true;
  234.         err = HOpen(myFileSpec.vRefNum, myFileSpec.parID,
  235.                     myFileSpec.name, fsRdPerm, &fileRefNum);
  236.     }
  237.  
  238.     if (err) {
  239.         AppDisposeDocument(frHndl);
  240.         return(err);
  241.     }
  242.  
  243.     (*frHndl)->fileState.fss    = myFileSpec;
  244.     (*frHndl)->fileState.refNum = fileRefNum;
  245.  
  246.     if (err = AppReadDocument(frHndl, reply.sfType)) {
  247.         AppDisposeDocument(frHndl);
  248.         return(err);
  249.     }
  250.  
  251.     if ((*frHndl)->fileState.readOnly) {
  252.         FSClose((*frHndl)->fileState.refNum);
  253.         (*frHndl)->fileState.fss.vRefNum = kInvalVRefNum;
  254.     }        /* If it's read-only, we don't need the file left open. */
  255.  
  256.     *result = frHndl;
  257.     return(err);
  258. }
  259.  
  260.  
  261.  
  262. /*****************************************************************************/
  263.  
  264.  
  265.  
  266. #pragma segment File
  267. OSErr    AppSaveDocument(FileRecHndl frHndl, WindowPtr window, short saveMode)
  268. {
  269.     Str255                closeOrQuit;
  270.     short                item, gameStatus;
  271.     StandardFileReply    reply;
  272.     OSErr                err;
  273.     short                fileRefNum;
  274.     DialogPtr            saveDialog;
  275.     Boolean                doPrompt;
  276.     Boolean                youLose;
  277.     OSType                theFileType;
  278.  
  279. /*    When entering, saveMode is set to the menu command number of the
  280. **    the item that prompted this.  Current settings are iSave, iSaveAs,
  281. **    iClose, and iQuit. */
  282.  
  283.     if (saveMode != iSaveAs) {                        /* If regular save... */
  284.         if (!AppDocumentDirty(frHndl))                /* If file clean...   */
  285.             return(noErr);                            /* Consider it saved. */
  286.     }
  287.  
  288.     pcpy(reply.sfFile.name, (*frHndl)->fileState.fss.name);
  289.  
  290.     if ((saveMode == iClose) || (saveMode == iQuit)) {
  291.         /* If implicit save... */
  292.  
  293.         GetIndString(closeOrQuit, rMiscStrings,
  294.                      (saveMode == iClose) ? ksClosing : ksQuitting);
  295.         ParamText(reply.sfFile.name, closeOrQuit, nil, nil);
  296.  
  297.         gameStatus = GameStatus(frHndl);
  298.         youLose = ((gameStatus == kYouLose) || (gameStatus == kYouLoseOnTime));
  299.         if ((gameStatus == kWhiteResigns) && ((*frHndl)->doc.myColor == WHITE))
  300.             youLose = true;
  301.         if ((gameStatus == kBlackResigns) && ((*frHndl)->doc.myColor == BLACK))
  302.             youLose = true;
  303.         if (youLose)
  304.             saveDialog = GetCenteredDialog(rNoYesCancel, nil, window, (WindowPtr)-1L);
  305.         else
  306.             saveDialog = GetCenteredDialog(rYesNoCancel, nil, window, (WindowPtr)-1L);
  307.  
  308.         if (saveDialog) {
  309.             OutlineDialogItem(saveDialog, kSaveYes);
  310.             DoSetCursor(&qd.arrow);
  311.             ModalDialog((ModalFilterProcPtr)KeyEquivFilter, &item);
  312.             DisposDialog(saveDialog);
  313.             if (youLose)
  314.                 if (item != kSaveCanceled)
  315.                     item = (item == kSaveYes) ? kSaveNo : kSaveYes;
  316.         }
  317.         else
  318.             item = kSaveYes;
  319.  
  320.         if (item != kSaveYes) {
  321.             err = noErr;
  322.             if (item == kSaveCanceled) err = userCanceledErr;
  323.             return(err);
  324.         }
  325.     }
  326.  
  327.     doPrompt = (
  328.         (saveMode == iSaveAs) ||
  329.         ((*frHndl)->fileState.fss.vRefNum == kInvalVRefNum)
  330.     );
  331.  
  332.     if (doPrompt) {
  333.         /* Prompt with SFGetFile if doing a Save As or have never saved before. */
  334.  
  335.         if (!DisplayPutFile(&reply))
  336.             return(userCanceledErr);
  337.                 /* User canceled the save. */
  338.  
  339.         if ((*frHndl)->fileState.fss.vRefNum != kInvalVRefNum)
  340.             FSClose((*frHndl)->fileState.refNum);
  341.                 /* Close the old file.  Don't respond to any error here because
  342.                 ** the user may be trying to do a save-as because their old file
  343.                 ** is bad.  If we fail to close the old file, and then respond
  344.                 ** to the error, the user won't get the opportunity to save
  345.                 ** their document to a new file.
  346.                 */
  347.  
  348.         theFileType = gameFileType;
  349.         if ((*frHndl)->doc.myColor == kMessageDoc) theFileType = mssgFileType;
  350.  
  351.         if (err = Create_OpenFile(&reply.sfFile, &fileRefNum, theFileType)) {
  352.             (*frHndl)->fileState.fss.vRefNum = kInvalVRefNum;
  353.             return(err);
  354.         }
  355.  
  356.         (*frHndl)->fileState.fss    = reply.sfFile;
  357.         (*frHndl)->fileState.refNum = fileRefNum;
  358.             /* This is the new file. */
  359.  
  360.         if (window) AppNewWindowTitle(window);
  361.     }
  362.  
  363.     if (err = AppWriteDocument(frHndl))
  364.         return(err);
  365.  
  366.     (*frHndl)->fileState.docDirty = false;
  367.     (*frHndl)->fileState.readOnly = false;
  368.     return(noErr);
  369. }
  370.  
  371.  
  372.  
  373. /*****************************************************************************/
  374.  
  375.  
  376.  
  377. /* ConvertOldToNewSFReply
  378. **
  379. ** struct StandardFileReply {            struct SFReply {
  380. **     Boolean     sfGood;                <-    Boolean good;
  381. **     Boolean     sfReplacing;        <-    Boolean copy;
  382. **     OSType         sfType;                <-    OSType fType;
  383. **     FSSpec        sfFile;
  384. **                     vRefNum;        <-    real vRefnum from (short vRefNum)
  385. **                     parID;            <-    real dirID from (short vRefNum)
  386. **                     name;            <-    Str63 fName;
  387. **     ScriptCode    sfScript;            <-    iuSystemScript
  388. **     short         sfFlags;            <-    0
  389. **     Boolean     sfIsFolder;            <-    false
  390. **     Boolean     sfIsVolume;            <-    false
  391. **     long        sfReserved1;        <-    0
  392. **     short        sfReserved2;        <-    0
  393. ** };
  394. **}; */
  395.  
  396. #pragma segment File
  397. void    ConvertOldToNewSFReply(SFReply *oldReply, StandardFileReply *newReply)
  398. {
  399.     OSErr    err;
  400.     long    ignoredProcID;
  401.  
  402.     newReply->sfGood        = oldReply->good;
  403.     newReply->sfReplacing    = oldReply->copy;        /* Correct assignment? */
  404.     newReply->sfType        = oldReply->fType;
  405.  
  406.     err = GetWDInfo(oldReply->vRefNum,
  407.                     &newReply->sfFile.vRefNum,
  408.                     &newReply->sfFile.parID,
  409.                     &ignoredProcID);
  410.     BlockMove((Ptr)&oldReply->fName,
  411.               (Ptr)&newReply->sfFile.name,
  412.               oldReply->fName[0]+1);
  413.  
  414.     /* Punt on the rest. */
  415.     newReply->sfScript        = iuSystemScript;
  416.     newReply->sfFlags        = 0;
  417.     newReply->sfIsFolder    = false;
  418.     newReply->sfIsVolume    = false;
  419.     newReply->sfReserved1    = 0;
  420.     newReply->sfReserved2    = 0;
  421. }
  422.  
  423.  
  424.  
  425. /*****************************************************************************/
  426.  
  427.  
  428.  
  429. /* Create_OpenFile
  430. **
  431. ** Opens the file specified by the passed FSSpec, creating it if it doesn't
  432. ** already exist. Refturns the refnum of the open file to the application.
  433. ** File Manager errors are reported and returned. */
  434.  
  435. #pragma segment File
  436. OSErr    Create_OpenFile(FSSpec *file, short *refNum, OSType theFileType)
  437. {
  438.     OSErr    err;
  439.  
  440.     err = HCreate(file->vRefNum, file->parID, file->name, gameCreator, theFileType);
  441.     if (err == dupFNErr) {
  442.  
  443.         /* The user already told Standard File to replace the old file
  444.            so let's get rid of it. */
  445.  
  446.         HDelete(file->vRefNum, file->parID, file->name);
  447.  
  448.         /* Try creating it again. */
  449.         err = HCreate(file->vRefNum, file->parID, file->name, gameCreator, theFileType);
  450.     }
  451.  
  452.     if (!err) {
  453.         err = HOpen(file->vRefNum, file->parID, file->name, fsRdWrPerm, refNum);
  454.         if (err)
  455.             HDelete(file->vRefNum, file->parID, file->name);
  456.     }
  457.  
  458.     return(err);
  459. }
  460.  
  461.  
  462.  
  463. /*****************************************************************************/
  464.  
  465.  
  466.  
  467. /* DisplayGetFile
  468. **
  469. ** Simple routine to display a list of files with our file type. */
  470.  
  471. #pragma segment File
  472. Boolean DisplayGetFile(StandardFileReply *reply)
  473. {
  474.     SFTypeList    typeList = {gameFileType, mssgFileType, typeChar};
  475.     Point        where = {100, 100};
  476.     SFReply        oldReply;
  477.  
  478.     if (gSystemVersion >= 0x0700)    /* If new standard file available... */
  479.         StandardGetFile(nil, 3, typeList, reply);
  480.  
  481.     else {
  482.         SFGetFile(where, "\pSelect a document to open.",
  483.                          nil, 3, typeList, nil, &oldReply);
  484.  
  485.         ConvertOldToNewSFReply(&oldReply, reply);
  486.     }
  487.  
  488.     return(reply->sfGood);
  489. }
  490.  
  491.  
  492.  
  493. /*****************************************************************************/
  494.  
  495.  
  496.  
  497. /* DisplayPutFile
  498. **
  499. ** Displays the StandardFile PutFile dialog box. Fills out the passed reply
  500. ** record, and returns the sfGood field as a result. */
  501.  
  502. #pragma segment File
  503. Boolean DisplayPutFile(StandardFileReply *reply)
  504. {
  505.     Str255        prompt;
  506.     Point        where = {100, 100};
  507.     SFReply        oldReply;
  508.  
  509.     GetIndString(prompt, rMiscStrings, ksSFprompt);
  510.  
  511.     if (gSystemVersion >= 0x0700)    /* If new standard file available... */
  512.         StandardPutFile(prompt, reply->sfFile.name, reply);
  513.     else {
  514.         SFPutFile(where, prompt, reply->sfFile.name, nil, &oldReply);
  515.         ConvertOldToNewSFReply(&oldReply, reply);
  516.     }
  517.  
  518.     return(reply->sfGood);
  519. }
  520.  
  521.  
  522.  
  523. /*****************************************************************************/
  524.  
  525.  
  526.  
  527. #pragma segment File
  528. void    IncNewFileNum(Boolean flag)
  529. {
  530.     gIncNewFileNumFlag = flag;
  531. }
  532.  
  533.  
  534.  
  535. /*****************************************************************************/
  536. /*****************************************************************************/
  537. /*****************************************************************************/
  538.  
  539.  
  540.  
  541. /* AppReadDocument
  542. **
  543. ** Reads in specified file into the data portion of a document handle. */
  544.  
  545. #pragma segment File
  546. OSErr    AppReadDocument(FileRecHndl frHndl, OSType ftype)
  547. {
  548.     short            fileRefNum, vers, i;
  549.     OSErr            err;
  550.     char            hstate;
  551.     Ptr                ptr1, ptr2;
  552.     long            count;
  553.     GameListHndl    gameMovesHndl;
  554.     Handle            textHndl;
  555.  
  556.     fileRefNum = (*frHndl)->fileState.refNum;
  557.  
  558.     err = SetFPos(fileRefNum, fsFromStart, 0);
  559.         /* Set the file position to the beginning of the file. */
  560.  
  561.     if (ftype != typeChar) {
  562.         if (!err) {        /* Read board info from file. */
  563.             hstate = LockHandleHigh((Handle)frHndl);
  564.             ptr1   = (Ptr)&((*frHndl)->doc);
  565.             ptr2   = (Ptr)&((*frHndl)->doc.endFileInfo1);
  566.             count  = (long)ptr2 - (long)ptr1;
  567.             err    = FSRead(fileRefNum, &count, ptr1);
  568.             HSetState((Handle)frHndl, hstate);
  569.             vers = (*frHndl)->doc.version;
  570.             if ((vers > kVersion) | (vers < kLeastVersion)) err = vers;
  571.         }
  572.  
  573.         if (!err) {
  574.             switch (vers) {
  575.                 case kLeastVersion:
  576.                     (*frHndl)->doc.version = kVersion;
  577.                     break;
  578.                 case kVersion:
  579.                     hstate = LockHandleHigh((Handle)frHndl);
  580.                     ptr1   = (Ptr)&((*frHndl)->doc.reconnectZone);
  581.                     ptr2   = (Ptr)&((*frHndl)->doc.endFileInfo2);
  582.                     count  = (long)ptr2 - (long)ptr1;
  583.                     err    = FSRead(fileRefNum, &count, ptr1);
  584.                     HSetState((Handle)frHndl, hstate);
  585.                     (*frHndl)->doc.compMovesWhite = (*frHndl)->doc.keepCMWhite;
  586.                     (*frHndl)->doc.compMovesBlack = (*frHndl)->doc.keepCMBlack;
  587.                     if ((*frHndl)->doc.timeLeft[0] != -1)
  588.                         for (i = 0; i < 2; ++i)
  589.                             (*frHndl)->doc.timeLeft[i] = (*frHndl)->doc.defaultTime[i];
  590.                     break;
  591.             }
  592.         }
  593.  
  594.         if (!err) {        /* Read move info from file. */
  595.             gameMovesHndl = (*frHndl)->doc.gameMoves;
  596.             count         = (*frHndl)->doc.numGameMoves * sizeof(GameElement);
  597.             SetHandleSize((Handle)gameMovesHndl, count);
  598.             err = MemError();
  599.             if (!err) {
  600.                 hstate = LockHandleHigh((Handle)gameMovesHndl);
  601.                 err = FSRead(fileRefNum, &count, (Ptr)(*gameMovesHndl));
  602.                 HSetState((Handle)gameMovesHndl, hstate);
  603.                 (*frHndl)->doc.timerRefTick = TickCount();
  604.                 (*frHndl)->doc.displayTime[0] = -1;
  605.                 (*frHndl)->doc.displayTime[1] = -1;
  606.                 (*frHndl)->doc.freezeTime[0] = -1;
  607.                 (*frHndl)->doc.freezeTime[1] = -1;
  608.                 (*frHndl)->fileState.docDirty = false;
  609.                 if (!err)
  610.                     if ((*frHndl)->doc.version != kVersion)
  611.                         err = kWrongVersion;
  612.             }
  613.         }
  614.     }
  615.  
  616.     if (!err) {        /* Read TextEdit text from file. */
  617.         textHndl = (Handle)(*frHndl)->doc.legalMoves;
  618.             /* There may be text saved to the file.  If there is any, this text
  619.             ** belongs in the out-box TextEdit control.  AppNewWindow creates
  620.             ** this control.  The problem is that a document is read before the
  621.             ** window for it is created.  Therefore the text will be placed
  622.             ** temporarily in the legalMoves handle.  Once GenerateLegalMoves
  623.             ** is called, the content of this handle will be overwritten.
  624.             ** GenereteLegalMoves isn't called until the window is created, so
  625.             ** this is an easy way to pass the text to AppNewWindow. */
  626.         count = 32000;
  627.             /* The size of the text isn't saved to disk.  This is the maximum
  628.             ** that we will accept. */
  629.         SetHandleSize(textHndl, count);
  630.         if (!(err = MemError())) {
  631.             hstate = LockHandleHigh(textHndl);
  632.             err    = FSRead(fileRefNum, &count, *textHndl);
  633.             HSetState((Handle)frHndl, hstate);
  634.             if (err == eofErr) err = noErr;
  635.             if (err) count = 0;
  636.             SetHandleSize(textHndl, count);
  637.                 /* Set the handle to the actual size of the text on disk. */
  638.         }
  639.     }
  640.  
  641.     return(err);
  642. }
  643.  
  644.  
  645.  
  646. /*****************************************************************************/
  647.  
  648.  
  649.  
  650. /* AppWriteDocument
  651. **
  652. ** Writes the data portion of a document handle to the specified file. */
  653.  
  654. #pragma segment File
  655. OSErr    AppWriteDocument(FileRecHndl frHndl)
  656. {
  657.     short            fileRefNum;
  658.     OSErr            err;
  659.     char            hstate;
  660.     Ptr                ptr1, ptr2;
  661.     long            count, fpos;
  662.     GameListHndl    gameMovesHndl;
  663.     TEHandle        te;
  664.     Handle            textHndl;
  665.     WindowPtr        window;
  666.     short            width;
  667.  
  668.     fileRefNum = (*frHndl)->fileState.refNum;
  669.  
  670.     err = SetFPos(fileRefNum, fsFromStart, 0);
  671.         /* Set the file position to the beginning of the file. */
  672.  
  673.     if (!err) {        /* Write board info to file. */
  674.         hstate = LockHandleHigh((Handle)frHndl);
  675.         ptr1   = (Ptr)&((*frHndl)->doc);
  676.         ptr2   = (Ptr)&((*frHndl)->doc.endFileInfo1);
  677.         count  = (long)ptr2 - (long)ptr1;
  678.         err    = FSWrite(fileRefNum, &count, ptr1);
  679.         HSetState((Handle)frHndl, hstate);
  680.     }
  681.  
  682.     if (!err) {        /* Write board info to file. */
  683.         hstate = LockHandleHigh((Handle)frHndl);
  684.         (*frHndl)->doc.reconnectZone[0]    = 0;
  685.         (*frHndl)->doc.reconnectMachine[0] = 0;
  686.         if ((*frHndl)->doc.twoPlayer) {
  687.             pcpy((*frHndl)->doc.reconnectZone,    (*frHndl)->doc.opponentZone);
  688.             pcpy((*frHndl)->doc.reconnectMachine, (*frHndl)->doc.opponentMachine);
  689.         }
  690.         (*frHndl)->doc.justBoardWindow = false;
  691.         if (window = (*frHndl)->fileState.window) {
  692.             width = window->portRect.right - window->portRect.left;
  693.             if (width == rJustBoardWindowWidth) (*frHndl)->doc.justBoardWindow = true;
  694.         }
  695.         (*frHndl)->doc.keepCMWhite = (*frHndl)->doc.compMovesWhite;
  696.         (*frHndl)->doc.keepCMBlack = (*frHndl)->doc.compMovesBlack;
  697.         ptr1  = (Ptr)&((*frHndl)->doc.reconnectZone);
  698.         ptr2  = (Ptr)&((*frHndl)->doc.endFileInfo2);
  699.         count = (long)ptr2 - (long)ptr1;
  700.         err   = FSWrite(fileRefNum, &count, ptr1);
  701.         HSetState((Handle)frHndl, hstate);
  702.     }
  703.  
  704.     if (!err) {        /* Write move info to file. */
  705.         gameMovesHndl = (*frHndl)->doc.gameMoves;
  706.         count         = (*frHndl)->doc.numGameMoves * sizeof(GameElement);
  707.         hstate = LockHandleHigh((Handle)gameMovesHndl);
  708.         err = FSWrite(fileRefNum, &count, (Ptr)(*gameMovesHndl));
  709.         HSetState((Handle)gameMovesHndl, hstate);
  710.     }
  711.  
  712.     if (!err) {        /* Write out-box TextEdit control text to file. */
  713.         te       = (*frHndl)->doc.message[kMessageOut];
  714.         textHndl = (*te)->hText;
  715.         count    = (*te)->teLength;
  716.         hstate   = LockHandleHigh(textHndl);
  717.         err      = FSWrite(fileRefNum, &count, *textHndl);
  718.         HSetState(textHndl, hstate);
  719.     }
  720.  
  721.     if (!err) {
  722.         err = GetFPos(fileRefNum, &fpos);
  723.         if (!err) err = SetEOF(fileRefNum, fpos);
  724.     }
  725.  
  726.     return(err);
  727. }
  728.  
  729.  
  730.  
  731. /*****************************************************************************/
  732.  
  733.  
  734.  
  735. #pragma segment File
  736. OSErr    AppDuplicateDocument(FileRecHndl oldFrHndl, FileRecHndl *newFrHndl)
  737. {
  738.     OSErr            err;
  739.     GameListHndl    oldMoves, newMoves;
  740.     Ptr                ptr1, ptr2;
  741.     long            oldMovesSize, dataSize;
  742.     Handle            oldText, newText;
  743.     TEHandle        te;
  744.     short            winNameType;
  745.  
  746.     winNameType = ksOrigName;
  747.     if ((*oldFrHndl)->doc.myColor == kMessageDoc) winNameType = ksMssgName;
  748.  
  749.     err = AppNewDocument(newFrHndl, winNameType);
  750.     if (!err) {
  751.         oldMoves = (*oldFrHndl)->doc.gameMoves;
  752.         newMoves = (**newFrHndl)->doc.gameMoves;
  753.         oldMovesSize = GetHandleSize((Handle)oldMoves);
  754.         SetHandleSize((Handle)newMoves, oldMovesSize);
  755.         err = MemError();
  756.         if (!err) {
  757.             ptr1     = (Ptr)&((*oldFrHndl)->doc);
  758.             ptr2     = (Ptr)&((*oldFrHndl)->doc.endFileInfo1);
  759.             dataSize = (long)ptr2 - (long)ptr1;
  760.             ptr2     = (Ptr)&((**newFrHndl)->doc);
  761.             BlockMove(ptr1, ptr2, dataSize);
  762.             (**newFrHndl)->doc.timeLeft[0] = (**newFrHndl)->doc.timeLeft[1] = -1;
  763.             BlockMove((Ptr)*oldMoves, (Ptr)*newMoves, oldMovesSize);
  764.             if ((*oldFrHndl)->doc.myColor == kMessageDoc) {
  765.                 te = (*oldFrHndl)->doc.message[kMessageOut];
  766.                 oldText = (*te)->hText;
  767.                 newText = (Handle)(**newFrHndl)->doc.legalMoves;
  768.                 SetHandleSize(newText, (*te)->teLength);
  769.                 err = MemError();
  770.                 if (!err) BlockMove(*oldText, *newText, (*te)->teLength);
  771.             }
  772.         }
  773.     }
  774.     return(err);
  775. }
  776.  
  777.  
  778.  
  779. /*****************************************************************************/
  780.  
  781.  
  782.  
  783. #pragma segment File
  784. OSErr    AppAutoLaunch(FileRecHndl frHndl)
  785. {
  786.     OSErr            err;
  787.     AEDesc            remoteDesc, aeDirDesc, listElem, fileList;
  788.     AppleEvent        aevt, aeReply;
  789.     char            hstate;
  790.     Str255            path;
  791.     Str255            app;
  792.     AliasHandle        dirAlias, fileAlias;
  793.  
  794.     err = noErr;
  795.  
  796.     if ((*frHndl)->doc.reconnectZone[0]) {
  797.  
  798.         DoSetCursor(*GetCursor(watchCursor));
  799.  
  800.         if (!GetRemoteFinderTarget(frHndl, &remoteDesc)) {
  801.  
  802.             err = AECreateAppleEvent('FNDR', 'sope', &remoteDesc,
  803.                                       kAutoGenerateReturnID, kAnyTransactionID, &aevt);
  804.             AEDisposeDesc(&remoteDesc);
  805.  
  806.             if (!err) {
  807.  
  808.                 hstate = LockHandleHigh((Handle)frHndl);
  809.                 pcpy(path, (*frHndl)->doc.reconnectPath);
  810.                 pcpy(app, path);
  811.                 pcat(app,  (*frHndl)->doc.reconnectApp);
  812.                 HSetState((Handle)frHndl, hstate);
  813.                 NewAliasMinimalFromFullPath(path[0], (path + 1), "\p", "\p", &dirAlias);
  814.                 NewAliasMinimalFromFullPath(app[0],  (app + 1),  "\p", "\p", &fileAlias);
  815.  
  816.                 err = AECreateList(nil, 0, false, &fileList);
  817.  
  818.                 if (!err) {
  819.                     hstate = LockHandleHigh((Handle)dirAlias);
  820.                     err = AECreateDesc(typeAlias, (Ptr)*dirAlias,
  821.                                        GetHandleSize((Handle)dirAlias), &aeDirDesc);
  822.                     HSetState((Handle)dirAlias, hstate);
  823.                 }
  824.                 DisposeHandle((Handle)dirAlias);
  825.  
  826.                 if (!err) {
  827.                     err = AEPutParamDesc(&aevt, keyDirectObject, &aeDirDesc);
  828.                     AEDisposeDesc(&aeDirDesc);
  829.                 }
  830.  
  831.                 if (!err) {
  832.                     hstate = LockHandleHigh((Handle)fileAlias);
  833.                     err = AECreateDesc(typeAlias, (Ptr)*fileAlias,
  834.                                        GetHandleSize((Handle)fileAlias), &listElem);
  835.                     HSetState((Handle)dirAlias, hstate);
  836.                 }
  837.                 DisposeHandle((Handle)fileAlias);
  838.  
  839.                 if (!err) {
  840.                     err = AEPutDesc(&fileList, 0, &listElem);
  841.                     AEDisposeDesc(&listElem);
  842.                 }
  843.  
  844.                 if (!err) {
  845.                     err = AEPutParamDesc(&aevt, 'fsel', &fileList);
  846.                     AEDisposeDesc(&fileList);
  847.                 }
  848.  
  849.                 if (!err) {
  850.                     err = AESend(&aevt, &aeReply,
  851.                                 (kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer),
  852.                                 kAENormalPriority, kAEDefaultTimeout, nil, nil);
  853.                     AEDisposeDesc(&aeReply);
  854.                 }
  855.  
  856.                 AEDisposeDesc(&aevt);
  857.  
  858.                 if (!err) SendGame(frHndl, kIsMove, "\pKibitz");
  859.  
  860.             }
  861.         }
  862.     }
  863.  
  864.     return(err);
  865. }
  866.  
  867.  
  868.  
  869.